#pragma once
#include <typeinfo>
#include <iostream>
#include <cassert>
#include"log.hpp"

class Any{
        private:
        class Holder {
            public:
                virtual const std::type_info& GetTypeInfo()=0;
                virtual Holder* Clone()=0;
                virtual ~Holder()=default;
            private:
        };
        template<class T>
        class Type:public Holder{
            public:
                //Type(const T& val):_val(val){};这个不支持string类型
                Type(const T& val){
                    _val=val;
                }
                Type(const Type& other){
                    _val=other.GetVal();
                }
                virtual const std::type_info& GetTypeInfo() override{
                    return typeid(T);
                }
                virtual Holder* Clone() override{
                    return new Type(_val);
                }
                T& GetVal() {
                    return _val;
                }
            private:
                T _val;
        };
        Holder *holder;
    public:
        Any():holder(nullptr){};
        template<class T>
        Any(const T& val){
            holder=new Type<T>(val);
        }
        Any(const Any& other){
            holder=other.holder->Clone();
        }
        // template<class T>
        // Any(const T val){
        //     holder=new Type<T>(val);
        // }
        ~Any(){
            if(holder!=nullptr)
                delete holder;
        }
        Any& operator=(const Any& other){
            if(this!=&other){
                if(holder!=nullptr)
                    delete holder;
                holder=other.holder->Clone();
            }
            return *this;
        }
        template<class T>
        Any& operator=(const T val){
            if(holder!=nullptr)
                delete holder;
            holder=new Type<T>(val);
            return *this;
        }
        //swap函数，因为容器都有这个
        void swap(Any& other){
            std::swap(holder,other.holder);
        }
        template<class T>
        T* GetVal() const {
            if(holder==nullptr){
                LOG(ly::LogLevel::ERROR)<<"Null pointer";
                assert(0);
            }
            if(holder->GetTypeInfo()==typeid(T)){
                return &(static_cast<Type<T>*>(holder))->GetVal();
            }
            else{
                LOG(ly::LogLevel::ERROR)<<"Type Error";
                assert(0);
            }
            return nullptr;
        }
        
};